﻿using System;
using System.Reflection;
using Ue.CQRS.Aop;
using Ue.CQRS.Bus;
using Ue.CQRS.Events;
using Ue.CQRS.Results;

namespace Ue.CQRS
{
    /// <summary>
    /// 事件标签，用来指定聚合对象中触发事件的方法
    /// </summary>
    [AttributeUsage(AttributeTargets.Method,AllowMultiple=false)]
    public class EventAttribute : Attribute,IAttribute,IMethodDecorator
    {
        public EventAttribute()
            : this(null) { }

        public EventAttribute(IEventBuilder eventFactory)
        {
            this.Level = 100;
            this.EventBuilder = eventFactory;
        }

        public string Name { get; set; }

        public int Level { get; set; }

        public TransferMode Mode { get; set; }

        public IEventBuilder EventBuilder { get; set; }

        #region IMethodDecorator

        public void OnExit(object sender, MethodBase method, object methodResult)
        {
            if (sender == null || methodResult == null)
            {
                throw new ArgumentNullException("eventResult");
            }

            if(string.IsNullOrEmpty(this.Name))
            {
                this.Name = this.GetEventName(method);
            }

            var eventResult = ResultFactory.Build(this, methodResult);
            var @event =EventFactory.Build(this.EventBuilder,this, sender, eventResult.EventArgs);

            EventSourceFactory.Build(sender).RaiseEvent(@event);
        }

        public void OnEntry(object sender, MethodBase method)
        {

        }

        public void OnException(object sender, MethodBase method, Exception exception)
        {

        }

        #endregion

        #region private methods

        private string GetEventName(MethodBase method)
        {
            if (!string.IsNullOrWhiteSpace(this.Name))
            {
                return this.Name;
            }

            var eventLeftName = method.Name.EndsWith("OnEvent")
                ? method.Name.Substring(0, method.Name.Length - 7)
                : method.Name;

            return string.Format("{0}{1}", eventLeftName, "Event");
        }

        #endregion
    }

    public enum TransferMode
    {
        /// <summary>
        /// 同步
        /// </summary>
        Sync,

        /// <summary>
        /// 异步
        /// </summary>
        Async
    }
}
